export default class DomUtil {
    /**
     * 对节点添加监听事件和回调
     * @param dom
     * @param type
     * @param listener
     * @returns
     */
    //@ts-ignore
    static listener = <K extends keyof GlobalEventHandlersEventMap>(
        dom: Node | Window,
        type: K,
        listener: (this: Node, ev: GlobalEventHandlersEventMap[K]) => any
    ) => {
        //@ts-ignore
        dom.addEventListener(type, listener)
        //@ts-ignore
        const remove = () => dom.removeEventListener(type, listener)
        return {
            remove
        }
    }

    /**
     * 获取管理点击或者触摸事件管理对象
     * @returns
     */
    static useTouch = () => {
        function getDirection(x: number, y: number) {
            if (x > y) {
                return 'horizontal'
            }
            if (y > x) {
                return 'vertical'
            }
            return ''
        }

        let startX = 0
        let startY = 0
        let deltaX = 0
        let deltaY = 0
        let offsetX = 0
        let offsetY = 0
        let direction: '' | 'vertical' | 'horizontal' = ''

        let isVertical = () => direction === 'vertical'
        let isHorizontal = () => direction === 'horizontal'

        const reset = () => {
            deltaX = 0
            deltaY = 0
            offsetX = 0
            offsetY = 0
            direction = ''
        }

        const start = (event: TouchEvent | Touch | Event | MouseEvent) => {
            const e = <TouchEvent & Touch & Event & MouseEvent>event
            reset()
            startX = e.clientX !== undefined ? e.clientX : e.touches[0].clientX
            startY = e.clientY !== undefined ? e.clientY : e.touches[0].clientY
        }

        const move = (event: TouchEvent | Touch | Event | MouseEvent) => {
            const e = <TouchEvent & Touch & Event & MouseEvent>event
            const touch =
                e.clientX !== undefined
                    ? {
                          clientX: e.clientX,
                          clientY: e.clientY
                      }
                    : e.touches[0]
            // safari back will set clientX to negative number
            deltaX = (touch.clientX < 0 ? 0 : touch.clientX) - startX
            deltaY = touch.clientY - startY
            offsetX = Math.abs(deltaX)
            offsetY = Math.abs(deltaY)

            // lock direction when distance is greater than a certain value
            const LOCK_DIRECTION_DISTANCE = 10
            if (!direction || (offsetX < LOCK_DIRECTION_DISTANCE && offsetY < LOCK_DIRECTION_DISTANCE)) {
                direction = getDirection(offsetX, offsetY)
            }
        }

        return {
            move,
            start,
            reset,
            startX,
            startY,
            deltaX,
            deltaY,
            offsetX,
            offsetY,
            direction,
            isVertical,
            isHorizontal
        }
    }

    /**
     *
     * @param div 目标，需要是absolute
     * @param fun 移动完毕之后的回调
     */
    static moveDiv(div: HTMLDivElement, onmouseup?: (data: { left: number; top: number }) => any) {
        const getRectVal = (val: any, fixed?: number) => {
            let valNum = parseFloat(val.split('px')[0])
            if (fixed !== undefined) valNum = parseFloat(valNum.toFixed(fixed))
            return valNum
        }

        div.style.position = 'absolute'
        div.style.width = div.offsetWidth + 'px'
        div.style.height = div.offsetHeight + 'px'
        div.style.left = div.offsetLeft + 'px'
        div.style.top = div.offsetTop + 'px'

        const move = {
            start: false,
            x: 0,
            y: 0
        }

        div.onmousedown = (event: MouseEvent) => {
            if (event.button === 0) {
                if (div.style.pointerEvents === 'none') return

                move.start = true
                move.x = event.x
                move.y = event.y
                document.onmousemove = (event: MouseEvent) => {
                    if (move.start) {
                        const divTRect = div.getBoundingClientRect()
                        const scaleV = divTRect.width / div.offsetWidth
                        let mX = event.x - move.x
                        let mY = event.y - move.y
                        mX = mX / scaleV
                        mY = mY / scaleV

                        const top = getRectVal(div.style.top) + mY
                        const left = getRectVal(div.style.left) + mX
                        div.style.top = top + 'px'
                        div.style.left = left + 'px'

                        move.x = event.x
                        move.y = event.y
                    }
                }
            }
        }

        div.onmousemove = () => {
            div.style.cursor = 'move'
        }

        div.onmouseup = (event: MouseEvent) => {
            const top = getRectVal(div.style.top, 0)
            const left = getRectVal(div.style.left, 0)
            const width = getRectVal(div.style.width, 0)
            const height = getRectVal(div.style.height, 0)
            div.style.top = top + 'px'
            div.style.left = left + 'px'
            div.style.width = width + 'px'
            div.style.height = height + 'px'

            move.start = false
            move.x = 0
            move.y = 0
            document.onmousemove = null
            if (onmouseup) onmouseup({ left, top })
        }
    }
}
